# Specify [source folder], [target folder]/<yyyyMMddHHmmss>, [maximum number] to achieve folder backup
# The target file cannot be in the source folder (to avoid dead loops), create if the target folder does not exist
# Based on Powershell

# input params:
param (
    $sourceFolder,
    $targetFolder, # default is $sourceFolder_devops_backup
    $backupVersionName, # default is [yyyyMMddHHmmss]
    $maxBackupCount, # default is 10
    $backupIgnore
)

# test
# $sourceFolder = 'D:\neo\3git\plugin_azureDevops_backup\demo\A'
# $targetFolder = ''
# $maxBackupCount = 3
# $backupIgnore = '*.txt'

# code
Write-Output '---params---'
Write-Output "sourceFolder: $sourceFolder"
Write-Output "targetFolder: $targetFolder"
Write-Output "backupVersionName: $backupVersionName"
Write-Output "maxBackupCount: $maxBackupCount"
Write-Output "backupIgnore:"
Write-Output $backupIgnore
Write-Output '---params end---'

try {

    # set default value: targetFolder
    if ($null -eq $targetFolder -or $targetFolder -eq "" -or $targetFolder -eq "undefined") {
        $targetFolder = $sourceFolder + "_devops_backup"
        Write-Output "set default [targetFolder]: $targetFolder"
    }
    # set default value: maxBackupCount
    if ($null -eq $maxBackupCount -or $maxBackupCount -eq "" -or $maxBackupCount -eq "undefined") {
        $maxBackupCount = 10
        Write-Output "set default [maxBackupCount]: $maxBackupCount"
    }

    if ($null -eq $backupIgnore -or $backupIgnore -eq "" -or $backupIgnore -eq "undefined") {
        $backupIgnore = @()
    }
    if($backupIgnore -is [string]){
        $backupIgnore = $backupIgnore -split "`r`n|`n|`r|,"
        $backupIgnore = $backupIgnore | Where-Object { $_ -ne '' }
        $backupIgnore = foreach ($line in $backupIgnore) { $line.Trim("\").Trim() }
        Write-Output "backupIgnore split result: $backupIgnore"
    }

    # set default value: backupVersionName
    if ($null -ne $backupVersionName -and $backupVersionName -ne "" -and $backupVersionName -ne "undefined") {
        if ($backupVersionName -match "\[.+\]" ) {
            $formatValue = $matches[0].Replace("[", "").Replace("]", "")
            $backupVersionName = Get-Date -Format "$formatValue"
        }    
    }
    else {
        $backupVersionName = Get-Date -Format "yyyyMMddHHmmss"
    }

    # validation: sourceFolder is required
    if (($null -eq $sourceFolder -or $sourceFolder -eq "") -or !(Test-Path $sourceFolder) ) {
        throw "The source folder [$sourceFolder] does not exist"
    }
    # Create the targetFolder if it does not exist
    if (!(Test-Path $targetFolder)) {
        New-Item -Path $targetFolder -ItemType Directory -Force | Out-Null
    }
    $sourceFolder = Convert-Path $sourceFolder
    $targetFolder = Convert-Path $targetFolder
    # validation: Avoid circular backup
    if (($targetFolder + "\").Contains($sourceFolder + "\")) {
        throw "The backup directory should not be under the source directory"
    }

    # Create the targetCurrentFolder if it does not exist
    $targetCurrentFolder = Join-Path $targetFolder $backupVersionName
    if (!(Test-Path $targetCurrentFolder)) {
        New-Item -Path $targetCurrentFolder -ItemType Directory -Force | Out-Null
        Write-Output "Create the current backup folder: $targetCurrentFolder"
    }

    # backup thisRun
    $AllFiles = Get-ChildItem $sourceFolder -Recurse | Sort-Object { $_.FullName.Length }
    foreach ($file in $AllFiles) {
        $FileRelativeName = $file.FullName.ToLower().Replace($sourceFolder.ToLower(), "").Trim("\")
        $needCopy = $True
        if ($null -ne $backupIgnore) {
            foreach ($ExcludePath in $backupIgnore) {
                if (($FileRelativeName -like $ExcludePath)) {
                    $needCopy = $False
                    Write-Output "CopyIgnore pattern: $ExcludePath"
                    Write-Output "CopyIgnore content: $FileRelativeName"
                    break
                }
            }
        }
        # Write-Output "--- like ---"
        # Write-Output $FileRelativeName
        # Write-Output $ExcludePath
        $destinationPath = Join-Path $targetCurrentFolder $FileRelativeName
        if ($needCopy) {
            $parentPath = Split-Path $destinationPath -Parent
            if (Test-Path $parentPath) {
                Copy-Item -Path $file.FullName -Destination $destinationPath -Force
            }
        }
    }

    # If the number of backups is greater than the maximum number of backups, delete the first backup record
    $AllDirectories = Get-ChildItem $targetFolder -Directory | Sort-Object Name
    if ($AllDirectories.Length -ge $MaxBackupCount) {
        $diff = $AllDirectories.Length - $MaxBackupCount
        for ($i = 0; $i -lt $diff; $i++) {
            $NeedRemoveDirName = $AllDirectories[$i]
            $NeedRemoveDirPath = Resolve-Path (Join-Path $targetFolder $NeedRemoveDirName)
            Remove-Item $NeedRemoveDirPath.Path -Recurse -Force
            Write-Output "Delete: $NeedRemoveDirPath" 
        }
    }
}
catch {
    Write-Output "An error occurred: $_"
    throw $_
}
Write-Output 'OK'